function createTask(i) {
  return () => {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(i);
      }, 1000);
    });
  };
}

class TaskQueue {
  constructor(max) {
    this.max = max;
    this.taskList = [];
    setTimeout(() => {
      this.run();
    }, 1000);
  }

  addTask(task) {
    this.taskList.push(task);
  }

  run() {
    const min = Math.min(this.max, this.taskList.length);
    for (let i = 0; i < min; i++) {
      this.max--;
      const task = this.taskList.shift();
      task()
        .then((res) => {
          console.log(res);
        })
        .finally(() => {
          this.max++;
          this.run();
        });
    }
  }
}

const taskQueue = new TaskQueue(5);
for (let i = 0; i < 20; i++) {
  const task = createTask(i);
  taskQueue.addTask(task);
}
